package com.eventlopp;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.util.Scanner;

/**
 * @author 罗俊华
 * @date 2021/8/25 - 1:47 下午
 */
@Slf4j
public class EventLoopClient {

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();


        ChannelFuture channelFuture = new Bootstrap()
                .group(eventLoopGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        // 使用 netty 自带的日志 handler
                        ch.pipeline().addFirst(new LoggingHandler(LogLevel.DEBUG));
                        ch.pipeline().addLast(new StringEncoder());
                    }

                })
//                1、连接到服务器，connect() 为一个异步非阻塞方法，调用者线程调用 connect() 之后立刻返回，由另一个线程执行 connect() 方法的具体逻辑来连接服务器
                .connect("localhost", 9904);

//          2、使用 sync() 让 当前线程阻塞，直到 成功建立与server之间的连接
//        channelFuture.sync();
        /**
         * 3、如果没有调用 sync() 方法，由于 connect() 方法是一个异步非阻塞方法，那么此时的 channel()调用之后获取到的是一个未完全建立连接的channel，向其发送数据的话，server不一定能收到
         */
        Channel channel = channelFuture.channel();
        /**
         * 4、注意，在 netty 中，发送数据的线程与调用 writeAndFlush()方法的线程不是同一个，idea调试的时候，断点只能暂停当前线程，不能暂停所有线程
         */
        channel.writeAndFlush("hello,zhangsan");

        // 2.1、 使用添加回调函数的方式异步非阻塞的处理结果


        channelFuture.addListener((ChannelFuture future) -> {
            log.debug("进入异步回调函数");
            Channel ch = future.channel();
            ch.writeAndFlush("回调函数发的消息");
        });

        channelFuture.addListener((ChannelFuture future) -> {
            Channel ch = future.channel();

            ch.closeFuture().addListener((ChannelFuture chf) -> {
                log.debug("channel关闭之后才能处理的操作，能保证一定在channel关闭以后才执行");
                // 关闭之后 eventLoopGroup 中还有一些线程，这些线程阻止了整个程序的停止
                eventLoopGroup.shutdownGracefully();
            });

            Scanner scanner = new Scanner(System.in);
            System.out.println("按q退出输入");
            while (true) {
                String s = scanner.nextLine();
                if ("q".equalsIgnoreCase(s)) {
                    /**
                     * 注意 channel 同样是一个异步非阻塞方法
                     */
                    ch.close();
                    // 所以在这里执行关闭 channel 之后的逻辑并不安全
//                    log.debug("channel关闭之后才能处理的操作");


                    break;
                }
                ch.writeAndFlush(s);
            }
        });



        log.debug("主线程执行完毕");


    }
}
